#ifndef __MP4__
#define __MP4__

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
typedef int int32_t;
typedef __int64 int64_t;

#define ATOM_PREAMBLE_SIZE  8
#define MAX_TRACKS          8
#define MAX_REQUEST_URL_LEN 2048
#define MAX_START_LEN       20
#define MAX_CACHE_AGE       (3600 * 24 * 7)


struct atom_t
{
	uint8_t type_[4];
	uint32_t size_;
#if __WORDSIZE == 64
	uint64_t start_;
	uint64_t end_;
#else
	uint32_t start_;
	uint32_t end_;
#endif
};

struct stts_table_t
{
	uint32_t sample_count_;
	uint32_t sample_duration_;
};

struct ctts_table_t
{
	uint32_t sample_count_;
	uint32_t sample_offset_;
};

struct stsc_table_t
{
	uint32_t chunk_;
	uint32_t samples_;
	uint32_t id_;
};

struct stbl_t
{
	uint8_t* start_;
	uint8_t* stts_;         // decoding time-to-sample
	uint8_t* stss_;         // sync sample
	uint8_t* stsc_;         // sample-to-chunk
	uint8_t* stsz_;         // sample size
	uint8_t* stco_;         // chunk offset
	uint8_t* ctts_;         // composition time-to-sample
};

struct minf_t
{
	uint8_t* start_;
	struct stbl_t stbl_;
};

struct mdia_t
{
	uint8_t* start_;
	uint8_t* mdhd_;
	struct minf_t minf_;
};

struct chunks_t
{
	uint32_t sample_;     // number of the first sample in the chunk
	uint32_t size_;       // number of samples in the chunk
	int32_t id_;          // for multiple codecs mode - not used
	uint32_t pos_;        // start byte position of chunk
};

struct samples_t
{
	uint32_t pts_;          // decoding/presentation time
	uint32_t size_;         // size in bytes
	uint32_t pos_;          // byte offset
	uint32_t cto_;          // composition time offset
};

struct trak_t
{
	uint8_t* start_;
	uint8_t* tkhd_;
	struct mdia_t mdia_;

	/* temporary indices */
	uint32_t chunks_size_;
	struct chunks_t* chunks_;

	uint32_t samples_size_;
	struct samples_t* samples_;
};

struct moov_t
{
	uint8_t* start_;
	uint32_t tracks_;
	uint8_t* mvhd_;
	struct trak_t traks_[MAX_TRACKS];
};

int32_t read_char(uint8_t const* buffer);
uint32_t read_int32(void const* buffer);
void write_int32(void* outbuffer, uint32_t value);
uint32_t atom_header_size(uint8_t* atom_bytes);
uint8_t* atom_read_header(uint8_t* buffer, struct atom_t* atom);
uint8_t* atom_skip(struct atom_t const* atom);
int32_t atom_is(struct atom_t const* atom, const char* type);
uint32_t stts_get_entries(uint8_t const* stts);
void stts_get_sample_count_and_duration(uint8_t const* stts, uint32_t idx, uint32_t* sample_count, uint32_t* sample_duration);

uint32_t ctts_get_entries(uint8_t const* ctts);
void ctts_get_sample_count_and_offset(uint8_t const* ctts, uint32_t idx, uint32_t* sample_count, uint32_t* sample_offset);
uint32_t ctts_get_samples(uint8_t const* ctts);
 uint32_t stsc_get_entries(uint8_t const* stsc);
void stsc_get_table(uint8_t const* stsc, uint32_t i, struct stsc_table_t *stsc_table);
uint32_t stsc_get_chunk(uint8_t* stsc, uint32_t sample);
uint32_t stsc_get_samples(uint8_t* stsc);
uint32_t stco_get_entries(uint8_t const* stco);
uint32_t stco_get_offset(uint8_t const* stco, int32_t idx);
uint32_t stsz_get_sample_size(uint8_t const* stsz);

uint32_t stsz_get_entries(uint8_t const* stsz);

uint32_t stsz_get_size(uint8_t const* stsz, uint32_t idx);

 uint32_t stts_get_duration(uint8_t const* stts);

 uint32_t stts_get_samples(uint8_t const* stts);

 uint32_t stts_get_sample(uint8_t const* stts, uint32_t time);

 uint32_t stts_get_time(uint8_t const* stts, uint32_t sample);


 void stbl_parse(struct stbl_t* stbl, uint8_t* buffer, uint32_t size);

 void minf_parse(struct minf_t* minf, uint8_t* buffer, uint32_t size);
 void mdia_parse(struct mdia_t* mdia, uint8_t* buffer, uint32_t size);

void trak_init(struct trak_t* trak);
void trak_exit(struct trak_t* trak);
void trak_parse(struct trak_t* trak, uint8_t* buffer, uint32_t size);

void moov_init(struct moov_t* moov);

void moov_exit(struct moov_t* moov);

 void trak_build_index(struct trak_t* trak);

 void trak_write_index(struct trak_t* trak, uint32_t start, uint32_t end);

 int32_t moov_parse(struct moov_t* moov, uint8_t* buffer, uint32_t size);

void stco_shift_offsets(uint8_t* stco, int32_t offset);
  void trak_shift_offsets(struct trak_t* trak, int32_t offset);

 void moov_shift_offsets(struct moov_t* moov, int32_t offset);

int64_t mvhd_get_time_scale(uint8_t* mvhd);

 void mvhd_set_duration(uint8_t* mvhd, int64_t duration);

  int64_t mdhd_get_time_scale(uint8_t* mdhd);

 void mdhd_set_duration(uint8_t* mdhd, uint32_t duration);

void tkhd_set_duration(uint8_t* tkhd, uint32_t duration);

 uint32_t stss_get_entries(uint8_t const* stss);

uint32_t stss_get_sample(uint8_t const* stss, uint32_t idx);

 uint32_t stss_get_nearest_keyframe(uint8_t const* stss, uint32_t sample);

uint32_t stbl_get_nearest_keyframe(struct stbl_t const* stbl, uint32_t sample);

 uint32_t moov_seek(uint8_t* moov_data, uint32_t size, double start_time, uint64_t* mdat_start, uint32_t* mdat_size, uint32_t offset);

void write_char(uint8_t* outbuffer, int32_t value);

int32_t atom_read_header_file(CFile* infile, struct atom_t* atom,int nStart);

void atom_write_header(uint8_t* outbuffer, struct atom_t* atom);

int atom_skip_file(CFile* infile, struct atom_t const* atom);


#endif

